package com.example.matchingengine.service.strategy;

import com.example.matchingengine.model.Order;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.ConcurrentHashMap;
import java.util.Map;

/**
 * 原型策略工厂类
 * 使用原型模式缓存和复用策略对象，提高性能
 */
@Slf4j
public class PrototypeStrategyFactory {
    
    // 策略原型缓存
    private static final Map<String, PrototypeStrategy> prototypeCache = new ConcurrentHashMap<>();
    
    // 静态初始化原型对象
    static {
        initializePrototypes();
    }
    
    /**
     * 初始化原型对象
     */
    private static void initializePrototypes() {
        try {
            prototypeCache.put("LIMIT_BUY", new LimitBuyStrategy());
            prototypeCache.put("LIMIT_SELL", new LimitSellStrategy());
            prototypeCache.put("MARKET_BUY", new MarketBuyStrategy());
            prototypeCache.put("MARKET_SELL", new MarketSellStrategy());
            
            log.info("策略原型缓存初始化完成，共缓存 {} 个策略原型", prototypeCache.size());
        } catch (Exception e) {
            log.error("策略原型缓存初始化失败: {}", e.getMessage(), e);
            throw new RuntimeException("策略原型缓存初始化失败", e);
        }
    }
    
    /**
     * 根据订单获取策略实例（通过克隆原型）
     * @param order 订单
     * @return 策略实例
     */
    public static MatchingStrategy getStrategy(Order order) {
        if (order == null) {
            throw new IllegalArgumentException("订单不能为空");
        }
        
        String strategyKey = getStrategyKey(order.getType(), order.getSide());
        return getStrategyByKey(strategyKey);
    }
    
    /**
     * 根据订单类型和方向获取策略实例
     * @param orderType 订单类型
     * @param orderSide 订单方向
     * @return 策略实例
     */
    public static MatchingStrategy getStrategy(Order.OrderType orderType, Order.OrderSide orderSide) {
        if (orderType == null || orderSide == null) {
            throw new IllegalArgumentException("订单类型和方向不能为空");
        }
        
        String strategyKey = getStrategyKey(orderType, orderSide);
        return getStrategyByKey(strategyKey);
    }
    
    /**
     * 根据策略键获取策略实例
     * @param strategyKey 策略键
     * @return 策略实例
     */
    private static MatchingStrategy getStrategyByKey(String strategyKey) {
        PrototypeStrategy prototype = prototypeCache.get(strategyKey);
        if (prototype == null) {
            throw new IllegalArgumentException("不支持的策略类型: " + strategyKey);
        }
        
        try {
            // 克隆原型对象
            PrototypeStrategy clonedStrategy = prototype.clone();
            // 重置状态
            clonedStrategy.reset();
            
            log.debug("通过原型模式创建策略实例: {}", strategyKey);
            return (MatchingStrategy) clonedStrategy;
        } catch (Exception e) {
            log.error("策略克隆失败: {}, 错误: {}", strategyKey, e.getMessage(), e);
            throw new RuntimeException("策略克隆失败: " + strategyKey, e);
        }
    }
    
    /**
     * 生成策略键
     * @param orderType 订单类型
     * @param orderSide 订单方向
     * @return 策略键
     */
    private static String getStrategyKey(Order.OrderType orderType, Order.OrderSide orderSide) {
        return orderType.name() + "_" + orderSide.name();
    }
    
    /**
     * 获取缓存的原型数量
     * @return 原型数量
     */
    public static int getPrototypeCount() {
        return prototypeCache.size();
    }
    
    /**
     * 清空原型缓存（主要用于测试）
     */
    public static void clearCache() {
        prototypeCache.clear();
        log.info("策略原型缓存已清空");
    }
}